<!DOCTYPE html>
            
<HTML>
<HEAD>
<meta name="booktitle" content="Developing Applications With Objective Caml" >
 <meta charset="ISO-8859-1"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<META name="GENERATOR" content="hevea 1.05-7 of 2000-02-24">
<META NAME="Author" CONTENT="Christian.Queinnec@lip6.fr">
<LINK rel=stylesheet type="text/css" href="videoc-ocda.css">
<script language="JavaScript" src="videoc.js"><!--
//--></script>
<TITLE>
 A Graphical Calculator
</TITLE>
</HEAD>
<BODY class="regularBody">
<A HREF="book-ora050.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora052.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
<HR>

<H2> A Graphical Calculator</H2>
<A NAME="sec-calc-vg"></A>
Let's consider the calculator example as described in the preceding
chapter on imperative programming (see page <A HREF="book-ora030.html#calc-v2">??</A>). We
will give it a graphical interface to make it more usable as a desktop
calculator.<BR>
<BR>
The graphical interface materializes the set of keys (digits and
functions) and an area for displaying results. Keys can be activated using
the graphical interface (and the mouse) or by typing on the keyboard.
Figure <A HREF="book-ora051.html#fig-calc-vg">5.9</A> shows the interface we are about to
construct.
<BLOCKQUOTE><DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV>
<DIV ALIGN=center>
<IMG SRC="book-ora018.gif">
</DIV>
<BR>
<DIV ALIGN=center>Figure 5.9: Graphical calculator.</DIV><BR>

<A NAME="fig-calc-vg"></A>
<DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV></BLOCKQUOTE>We reuse the functions for drawing boxes as described on page
<A HREF="book-ora048.html#sec-boites">??</A>. We define the following type:


<PRE><BR># <B>type</B><CODE> </CODE>calc_state<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE>{<CODE> </CODE>s<CODE> </CODE><CODE>:</CODE><CODE> </CODE>state;<CODE> </CODE>k<CODE> </CODE><CODE>:</CODE><CODE> </CODE><TT>(</TT>box_config<CODE> </CODE><CODE>*</CODE><CODE> </CODE>key<CODE> </CODE><CODE>*</CODE><CODE> </CODE>string<CODE> </CODE><TT>)</TT><CODE> </CODE>list;<CODE> </CODE>v<CODE> </CODE><CODE>:</CODE><CODE> </CODE>box_config<CODE> </CODE>}<CODE> </CODE>;;<BR>

</PRE>

It contains the state of the calculator, the list of boxes corresponding
to the keys and the visualization box. We plan to construct a calculator
that is easily modifiable. Therefore, we parameterize the construction
of the interface with an association list:


<PRE><BR># <B>let</B><CODE> </CODE>descr_calc<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE>[</CODE><CODE> </CODE><CODE> </CODE><TT>(</TT>Digit<CODE> </CODE><CODE>0</CODE><CODE>,</CODE><CODE>"0"</CODE><TT>)</TT>;<CODE> </CODE><CODE> </CODE><TT>(</TT>Digit<CODE> </CODE><CODE>1</CODE><CODE>,</CODE><CODE>"1"</CODE><TT>)</TT>;<CODE> </CODE><CODE> </CODE><TT>(</TT>Digit<CODE> </CODE><CODE>2</CODE><CODE>,</CODE><CODE>"2"</CODE><TT>)</TT>;<CODE> </CODE><CODE> </CODE><TT>(</TT>Equals<CODE>,</CODE><CODE> </CODE><CODE>"="</CODE><TT>)</TT>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT>Digit<CODE> </CODE><CODE>3</CODE><CODE>,</CODE><CODE>"3"</CODE><TT>)</TT>;<CODE> </CODE><CODE> </CODE><TT>(</TT>Digit<CODE> </CODE><CODE>4</CODE><CODE>,</CODE><CODE>"4"</CODE><TT>)</TT>;<CODE> </CODE><CODE> </CODE><TT>(</TT>Digit<CODE> </CODE><CODE>5</CODE><CODE>,</CODE><CODE>"5"</CODE><TT>)</TT>;<CODE> </CODE><CODE> </CODE><TT>(</TT>Plus<CODE>,</CODE><CODE> </CODE><CODE>"+"</CODE><TT>)</TT>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT>Digit<CODE> </CODE><CODE>6</CODE><CODE>,</CODE><CODE>"6"</CODE><TT>)</TT>;<CODE> </CODE><CODE> </CODE><TT>(</TT>Digit<CODE> </CODE><CODE>7</CODE><CODE>,</CODE><CODE>"7"</CODE><TT>)</TT>;<CODE> </CODE><CODE> </CODE><TT>(</TT>Digit<CODE> </CODE><CODE>8</CODE><CODE>,</CODE><CODE>"8"</CODE><TT>)</TT>;<CODE> </CODE><CODE> </CODE><TT>(</TT>Minus<CODE>,</CODE><CODE> </CODE><CODE>"-"</CODE><TT>)</TT>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT>Digit<CODE> </CODE><CODE>9</CODE><CODE>,</CODE><CODE>"9"</CODE><TT>)</TT>;<CODE> </CODE><CODE> </CODE><TT>(</TT>Recall<CODE>,</CODE><CODE>"RCL"</CODE><TT>)</TT>;<CODE> </CODE><TT>(</TT>Div<CODE>,</CODE><CODE> </CODE><CODE>"/"</CODE><TT>)</TT>;<CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT>Times<CODE>,</CODE><CODE> </CODE><CODE>"*"</CODE><TT>)</TT>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT>Off<CODE>,</CODE><CODE>"AC"</CODE><TT>)</TT>;<CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT>Store<CODE>,</CODE><CODE> </CODE><CODE>"STO"</CODE><TT>)</TT>;<CODE> </CODE><TT>(</TT>Clear<CODE>,</CODE><CODE>"CE/C"</CODE><TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE>]</CODE><CODE> </CODE>;;<BR>

</PRE>
<BR>
<BR>

<H5> Generation of key boxes</H5>
At the beginning of this description we construct a list of key boxes. The
function <TT>gen_boxes</TT> takes as parameters the description
(<TT>descr</TT>), the number of the column (<TT>n</TT>), the separation
between boxes (<TT>wsep</TT>), the separation between the text and
the borders of the box (<TT>wsepint</TT>) and the size of the board
(<TT>wbord</TT>). This function returns the list of key boxes as well
as the visualization box. To calculate these placements, we define the
auxiliary functions <TT>max_xy</TT> for calculating the maximal size
of a list of complete pairs and <TT>max_lbox</TT> for calculating the
maximal positions of a list of boxes.


<PRE><BR># <B>let</B><CODE> </CODE>gen_xy<CODE> </CODE>vals<CODE> </CODE>comp<CODE> </CODE>o<CODE> </CODE><CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>List.fold_left<CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE><CODE> </CODE>a<CODE> </CODE><TT>(</TT>x<CODE>,</CODE>y<TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE>comp<CODE> </CODE><TT>(</TT>fst<CODE> </CODE>a<TT>)</TT><CODE> </CODE>x<CODE>,</CODE>comp<CODE> </CODE><TT>(</TT>snd<CODE> </CODE>a<TT>)</TT><CODE> </CODE>y<TT>)</TT><CODE> </CODE>o<CODE> </CODE>vals<CODE> </CODE>;;<BR><CODE>val gen_xy : ('a * 'a) list -&gt; ('b -&gt; 'a -&gt; 'b) -&gt; 'b * 'b -&gt; 'b * 'b = &lt;fun&gt;</CODE><BR># <B>let</B><CODE> </CODE>max_xy<CODE> </CODE>vals<CODE> </CODE><CODE>=</CODE><CODE> </CODE>gen_xy<CODE> </CODE>vals<CODE> </CODE>max<CODE> </CODE><TT>(</TT>min_int<CODE>,</CODE>min_int<TT>)</TT>;;<BR><CODE>val max_xy : (int * int) list -&gt; int * int = &lt;fun&gt;</CODE><BR># <B>let</B><CODE> </CODE>max_boxl<CODE> </CODE>l<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>bmax<CODE> </CODE><TT>(</TT>mx<CODE>,</CODE>my<TT>)</TT><CODE> </CODE>b<CODE> </CODE><CODE>=</CODE><CODE> </CODE>max<CODE> </CODE>mx<CODE> </CODE>b<CODE>.</CODE>x<CODE>,</CODE><CODE> </CODE>max<CODE> </CODE>my<CODE> </CODE>b<CODE>.</CODE>y<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>List.fold_left<CODE> </CODE>bmax<CODE> </CODE><CODE> </CODE><TT>(</TT>min_int<CODE>,</CODE>min_int<TT>)</TT><CODE> </CODE>l<CODE> </CODE>;;<BR><CODE>val max_boxl : box_config list -&gt; int * int = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
Here is the principal function <TT>gen_boxes</TT> for creating the
interface.


<PRE><BR># <B>let</B><CODE> </CODE>gen_boxes<CODE> </CODE>descr<CODE> </CODE>n<CODE> </CODE>wsep<CODE> </CODE>wsepint<CODE> </CODE>wbord<CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>l_l<CODE> </CODE><CODE>=</CODE><CODE> </CODE>List.length<CODE> </CODE>descr<CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>nb_lig<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>if</B><CODE> </CODE>l_l<CODE> </CODE><B>mod</B><CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>0</CODE><CODE> </CODE><B>then</B><CODE> </CODE>l_l<CODE> </CODE><CODE>/</CODE><CODE> </CODE>n<CODE> </CODE><B>else</B><CODE> </CODE>l_l<CODE> </CODE><CODE>/</CODE><CODE> </CODE>n<CODE> </CODE><CODE>+</CODE><CODE> </CODE><CODE>1</CODE><CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>ls<CODE> </CODE><CODE>=</CODE><CODE> </CODE>List.map<CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE><TT>(</TT>x<CODE>,</CODE>y<TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE>Graphics.text_size<CODE> </CODE>y<TT>)</TT><CODE> </CODE>descr<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>sx<CODE>,</CODE>sy<CODE> </CODE><CODE>=</CODE><CODE> </CODE>max_xy<CODE> </CODE><CODE> </CODE>ls<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>sx<CODE>,</CODE>sy<CODE>=</CODE><CODE> </CODE>sx<CODE>+</CODE>wsepint<CODE> </CODE><CODE>,</CODE>sy<CODE>+</CODE>wsepint<CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>r<CODE> </CODE><CODE>=</CODE><CODE> </CODE>ref<CODE> </CODE>[]<CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>for</B><CODE> </CODE>i<CODE>=</CODE><CODE>0</CODE><CODE> </CODE><B>to</B><CODE> </CODE>l_l<CODE>-</CODE><CODE>1</CODE><CODE> </CODE><B>do</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>px<CODE> </CODE><CODE>=</CODE><CODE> </CODE>i<CODE> </CODE><B>mod</B><CODE> </CODE>n<CODE> </CODE><B>and</B><CODE> </CODE>py<CODE> </CODE><CODE>=</CODE><CODE> </CODE>i<CODE> </CODE><CODE>/</CODE><CODE> </CODE>n<CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>b<CODE> </CODE><CODE>=</CODE><CODE> </CODE>{<CODE> </CODE>x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>wsep<CODE> </CODE><CODE>*</CODE><CODE> </CODE><TT>(</TT>px<CODE>+</CODE><CODE>1</CODE><TT>)</TT><CODE> </CODE><CODE>+</CODE><CODE> </CODE><TT>(</TT>sx<CODE>+</CODE><CODE>2</CODE><CODE>*</CODE>wbord<TT>)</TT><CODE> </CODE><CODE>*</CODE><CODE> </CODE>px<CODE> </CODE><CODE> </CODE>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>y<CODE> </CODE><CODE>=</CODE><CODE> </CODE>wsep<CODE> </CODE><CODE>*</CODE><CODE> </CODE><TT>(</TT>py<CODE>+</CODE><CODE>1</CODE><TT>)</TT><CODE> </CODE><CODE>+</CODE><CODE> </CODE><TT>(</TT>sy<CODE>+</CODE><CODE>2</CODE><CODE>*</CODE>wbord<TT>)</TT><CODE> </CODE><CODE>*</CODE><CODE> </CODE>py<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>w<CODE> </CODE><CODE>=</CODE><CODE> </CODE>sx;<CODE> </CODE>h<CODE> </CODE><CODE>=</CODE><CODE> </CODE>sy<CODE> </CODE>;<CODE> </CODE>bw<CODE> </CODE><CODE>=</CODE><CODE> </CODE>wbord;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>r<CODE>=</CODE>Top;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>b1_col<CODE> </CODE><CODE>=</CODE><CODE> </CODE>gray1;<CODE> </CODE><CODE> </CODE>b2_col<CODE> </CODE><CODE>=</CODE><CODE> </CODE>gray3;<CODE> </CODE>b_col<CODE> </CODE><CODE>=</CODE>gray2}<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>r<CODE>:=</CODE><CODE> </CODE>b<CODE>::!</CODE>r<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>done</B>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>mpx<CODE>,</CODE>mpy<CODE> </CODE><CODE>=</CODE><CODE> </CODE>max_boxl<CODE> </CODE><CODE>!</CODE>r<CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>upx<CODE>,</CODE>upy<CODE> </CODE><CODE>=</CODE><CODE> </CODE>mpx<CODE>+</CODE>sx<CODE>+</CODE>wbord<CODE>+</CODE>wsep<CODE>,</CODE>mpy<CODE>+</CODE>sy<CODE>+</CODE>wbord<CODE>+</CODE>wsep<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE><TT>(</TT>wa<CODE>,</CODE>ha<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE>Graphics.text_size<CODE> </CODE><CODE>"        0"</CODE><CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>v<CODE> </CODE><CODE>=</CODE><CODE> </CODE>{<CODE> </CODE>x<CODE>=</CODE><TT>(</TT>upx<CODE>-</CODE><TT>(</TT>wa<CODE>+</CODE>wsepint<CODE> </CODE><CODE>+</CODE>wbord<TT>)</TT><TT>)</TT><CODE>/</CODE><CODE>2</CODE><CODE> </CODE>;<CODE> </CODE>y<CODE>=</CODE><CODE> </CODE>upy<CODE>+</CODE><CODE> </CODE>wsep;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>w<CODE>=</CODE>wa<CODE>+</CODE>wsepint;<CODE> </CODE>h<CODE> </CODE><CODE>=</CODE><CODE> </CODE>ha<CODE> </CODE><CODE>+</CODE>wsepint;<CODE> </CODE>bw<CODE> </CODE><CODE>=</CODE><CODE> </CODE>wbord<CODE> </CODE><CODE>*</CODE><CODE>2</CODE>;<CODE> </CODE>r<CODE>=</CODE>Flat<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>b1_col<CODE> </CODE><CODE>=</CODE><CODE> </CODE>gray1;<CODE> </CODE><CODE> </CODE>b2_col<CODE> </CODE><CODE>=</CODE><CODE> </CODE>gray3;<CODE> </CODE>b_col<CODE> </CODE><CODE>=</CODE>Graphics.black}<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>upx<CODE>,</CODE><TT>(</TT>upy<CODE>+</CODE>wsep<CODE>+</CODE>ha<CODE>+</CODE>wsepint<CODE>+</CODE>wsep<CODE>+</CODE><CODE>2</CODE><CODE>*</CODE>wbord<TT>)</TT><CODE>,</CODE>v<CODE>,</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>List.map2<CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE>b<CODE> </CODE><TT>(</TT>x<CODE>,</CODE>y<TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE>b<CODE>,</CODE>x<CODE>,</CODE>y<CODE> </CODE><TT>)</TT><CODE> </CODE><TT>(</TT>List.rev<CODE> </CODE><CODE>!</CODE>r<TT>)</TT><CODE> </CODE>descr;;<BR><CODE>val gen_boxes :</CODE><BR><CODE>  ('a * string) list -&gt;</CODE><BR><CODE>  int -&gt;</CODE><BR><CODE>  int -&gt;</CODE><BR><CODE>  int -&gt; int -&gt; int * int * box_config * (box_config * 'a * string) list =</CODE><BR><CODE>  &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>

<H5> Interaction</H5>
Since we would also like to reuse the skeleton proposed on page
<A HREF="book-ora050.html#sec-squelette">??</A> for interaction, we define the functions for
keyboard and mouse control, which are integrated in this skeleton. The
function for controlling the keyboard is very simple. It passes the
translation of a character value of type <I>key</I> to the function
<TT>transition</TT> of the calculator and then displays the text
associated with the calculator state.


<PRE><BR># <B>let</B><CODE> </CODE>f_key<CODE> </CODE>cs<CODE> </CODE>c<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>transition<CODE> </CODE>cs<CODE>.</CODE>s<CODE> </CODE><TT>(</TT>translation<CODE> </CODE>c<TT>)</TT>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>erase_box<CODE> </CODE>cs<CODE>.</CODE>v;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_string_in_box<CODE> </CODE>Right<CODE> </CODE><TT>(</TT>string_of_int<CODE> </CODE>cs<CODE>.</CODE>s<CODE>.</CODE>vpr<TT>)</TT><CODE> </CODE>cs<CODE>.</CODE>v<CODE> </CODE>Graphics.white<CODE> </CODE>;;<BR><CODE>val f_key : calc_state -&gt; char -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The control of the mouse is a bit more complex. It requires verification
that the position of the mouse click is actually in one of the key boxes. For
this we first define the auxiliary function <TT>mem</TT>, which verifies
membership of a position within a rectangle.


<PRE><BR># <B>let</B><CODE> </CODE>mem<CODE> </CODE><TT>(</TT>x<CODE>,</CODE>y<TT>)</TT><CODE> </CODE><TT>(</TT>x0<CODE>,</CODE>y0<CODE>,</CODE>w<CODE>,</CODE>h<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT>x<CODE> </CODE><CODE>&gt;=</CODE><CODE> </CODE>x0<TT>)</TT><CODE> </CODE><CODE>&amp;&amp;</CODE><CODE> </CODE><TT>(</TT>x<CODE>&lt;</CODE><CODE> </CODE>x0<CODE>+</CODE>w<TT>)</TT><CODE> </CODE><CODE>&amp;&amp;</CODE><CODE> </CODE><TT>(</TT>y<CODE>&gt;=</CODE>y0<TT>)</TT><CODE> </CODE><CODE>&amp;&amp;</CODE><CODE> </CODE><TT>(</TT><CODE> </CODE>y<CODE>&lt;</CODE>y0<CODE>+</CODE>h<TT>)</TT>;;<BR><CODE>val mem : int * int -&gt; int * int * int * int -&gt; bool = &lt;fun&gt;</CODE><BR># <B>let</B><CODE> </CODE>f_mouse<CODE> </CODE>cs<CODE> </CODE>x<CODE> </CODE>y<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>try</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>b<CODE>,</CODE>t<CODE>,</CODE>s<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>List.find<CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE><TT>(</TT>b<CODE>,_,_</CODE><TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>mem<CODE> </CODE><TT>(</TT>x<CODE>,</CODE>y<TT>)</TT><CODE> </CODE><TT>(</TT>b<CODE>.</CODE>x<CODE>+</CODE>b<CODE>.</CODE>bw<CODE>,</CODE>b<CODE>.</CODE>y<CODE>+</CODE>b<CODE>.</CODE>bw<CODE>,</CODE>b<CODE>.</CODE>w<CODE>,</CODE>b<CODE>.</CODE>h<TT>)</TT><TT>)</TT><CODE> </CODE>cs<CODE>.</CODE>k<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>transition<CODE> </CODE>cs<CODE>.</CODE>s<CODE> </CODE>t;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>erase_box<CODE> </CODE>cs<CODE>.</CODE>v;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_string_in_box<CODE> </CODE>Right<CODE> </CODE><TT>(</TT>string_of_int<CODE> </CODE>cs<CODE>.</CODE>s<CODE>.</CODE>vpr<CODE> </CODE><TT>)</TT><CODE> </CODE>cs<CODE>.</CODE>v<CODE> </CODE>Graphics.white<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>with</B><CODE> </CODE>Not_found<CODE> </CODE>-&gt;<CODE> </CODE>();;<BR><CODE>val f_mouse : calc_state -&gt; int -&gt; int -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The function <TT>f_mouse</TT> looks whether the position of the mouse
during the click is reallydwell within one of the boxes corresponding to a
key. If it is, it passes the corresponding key to the transition function
and displays the result, otherwise it will not do anything.<BR>
<BR>
The function <TT>f_exc</TT> handles the exceptions which can arise
during program execution.


<PRE><BR># <B>let</B><CODE> </CODE>f_exc<CODE> </CODE>cs<CODE> </CODE>ex<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><B>match</B><CODE> </CODE>ex<CODE> </CODE><B>with</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>Division_by_zero<CODE> </CODE>-&gt;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>transition<CODE> </CODE>cs<CODE>.</CODE>s<CODE> </CODE>Clear;<CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>erase_box<CODE> </CODE>cs<CODE>.</CODE>v;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_string_in_box<CODE> </CODE>Right<CODE> </CODE><CODE>"Div 0"</CODE><CODE> </CODE>cs<CODE>.</CODE>v<CODE> </CODE><TT>(</TT>Graphics.red<TT>)</TT><BR><CODE> </CODE><CODE>|</CODE><CODE> </CODE>Invalid_key<CODE> </CODE>-&gt;<CODE> </CODE>()<BR><CODE> </CODE><CODE>|</CODE><CODE> </CODE>Key_off<CODE> </CODE>-&gt;<CODE> </CODE>raise<CODE> </CODE>End<BR><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>_</CODE><CODE> </CODE><CODE> </CODE>-&gt;<CODE> </CODE>raise<CODE> </CODE>ex;;<BR><CODE>val f_exc : calc_state -&gt; exn -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
In the case of a division by zero, it restarts in the initial state of
the calculator and displays an error message on its screen. Invalid keys
are simply ignored. Finally, the exception <TT>Key_off</TT> raises the
exception <TT>End</TT> to terminate the loop of the skeleton.<BR>
<BR>

<H5> Initialization and termination</H5>
The initialization of the calculator requires calculation of the window
size. The following function creates the graphical information of the
boxes from a key/text association and returns the size of the principal
window.


<PRE><BR># <B>let</B><CODE> </CODE>create_e<CODE> </CODE>k<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Graphics.close_graph<CODE> </CODE>();<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Graphics.open_graph<CODE> </CODE><CODE>" 10x10"</CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>mx<CODE>,</CODE>my<CODE>,</CODE>v<CODE>,</CODE>lb<CODE> </CODE><CODE>=</CODE><CODE> </CODE>gen_boxes<CODE> </CODE>k<CODE> </CODE><CODE>4</CODE><CODE> </CODE><CODE>4</CODE><CODE> </CODE><CODE>5</CODE><CODE> </CODE><CODE>2</CODE><CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>s<CODE> </CODE><CODE>=</CODE><CODE> </CODE>{lcd<CODE>=</CODE><CODE>0</CODE>;<CODE> </CODE>lka<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>false</B>;<CODE> </CODE>loa<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Equals;<CODE> </CODE>vpr<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>0</CODE>;<CODE> </CODE>mem<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>0</CODE>}<CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>mx<CODE>,</CODE>my<CODE>,{</CODE>s<CODE>=</CODE>s;<CODE> </CODE>k<CODE>=</CODE>lb;v<CODE>=</CODE>v};;<BR><CODE>val create_e : (key * string) list -&gt; int * int * calc_state = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The initialization function makes use of the result of the preceding function.


<PRE><BR># <B>let</B><CODE> </CODE>f_init<CODE> </CODE>mx<CODE> </CODE>my<CODE> </CODE>cs<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Graphics.close_graph();<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Graphics.open_graph<CODE> </CODE><TT>(</TT><CODE>" "</CODE><CODE>^</CODE><TT>(</TT>string_of_int<CODE> </CODE>mx<TT>)</TT><CODE>^</CODE><CODE>"x"</CODE><CODE>^</CODE><TT>(</TT>string_of_int<CODE> </CODE>my<TT>)</TT><TT>)</TT>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Graphics.set_color<CODE> </CODE>gray2;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Graphics.fill_rect<CODE> </CODE><CODE>0</CODE><CODE> </CODE><CODE>0</CODE><CODE> </CODE><TT>(</TT>mx<CODE>+</CODE><CODE>1</CODE><TT>)</TT><CODE> </CODE><TT>(</TT>my<CODE>+</CODE><CODE>1</CODE><TT>)</TT>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>List.iter<CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE><TT>(</TT>b<CODE>,_,_</CODE><TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE>draw_box<CODE> </CODE>b<TT>)</TT><CODE> </CODE>cs<CODE>.</CODE>k;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>List.iter<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE><TT>(</TT>b<CODE>,_,</CODE>s<TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE>draw_string_in_box<CODE> </CODE>Center<CODE> </CODE>s<CODE> </CODE>b<CODE> </CODE>Graphics.black<TT>)</TT><CODE> </CODE>cs<CODE>.</CODE>k<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_box<CODE> </CODE>cs<CODE>.</CODE>v;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>erase_box<CODE> </CODE>cs<CODE>.</CODE>v;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_string_in_box<CODE> </CODE>Right<CODE> </CODE><CODE>"hello"</CODE><CODE> </CODE>cs<CODE>.</CODE>v<CODE> </CODE><TT>(</TT>Graphics.white<TT>)</TT>;;<BR><CODE>val f_init : int -&gt; int -&gt; calc_state -&gt; unit -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
Finally the termination function closes the graphical window.


<PRE><BR># <B>let</B><CODE> </CODE>f_end<CODE> </CODE>e<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Graphics.close_graph();;<BR><CODE>val f_end : 'a -&gt; unit -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The function <TT>go</TT> is parameterized by a description and starts
the interactive loop.


<PRE><BR># <B>let</B><CODE> </CODE>go<CODE> </CODE>descr<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>mx<CODE>,</CODE>my<CODE>,</CODE>e<CODE> </CODE><CODE>=</CODE><CODE> </CODE>create_e<CODE> </CODE>descr<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>skel<CODE> </CODE><TT>(</TT>f_init<CODE> </CODE>mx<CODE> </CODE>my<CODE> </CODE>e<TT>)</TT><CODE> </CODE><TT>(</TT>f_end<CODE> </CODE>e<TT>)</TT><CODE> </CODE><TT>(</TT>f_key<CODE> </CODE>e<TT>)</TT><CODE> </CODE><TT>(</TT>f_mouse<CODE> </CODE>e<TT>)</TT><CODE> </CODE><TT>(</TT>f_exc<CODE> </CODE>e<TT>)</TT>;;<BR><CODE>val go : (key * string) list -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The call to <TT>go descr_calc</TT> corresponds to the figure <A HREF="book-ora051.html#fig-calc-vg">5.9</A>.<BR>
<BR>
<BR>
<BR>

<BR>
<BR>
<HR>
<A HREF="book-ora050.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora052.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
</BODY>
</HTML>
